home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 1 / Cream of the Crop 1.iso / PROGRAM / TODOLIST.ARJ / TODOLIST.CPP < prev    next >
C/C++ Source or Header  |  1992-01-29  |  18KB  |  688 lines

  1. //---------------------------------------------------------------------
  2. //
  3. //  TODOLIST.CPP - part of TODO example program
  4. //
  5. //      Copyright (c) 1991 by Borland International
  6. //      All Rights Reserved.
  7. //
  8. //---------------------------------------------------------------------
  9.  
  10. #if !defined( __STRSTREAM_H )
  11. #include <strstream.h>
  12. #endif  // __STRSTREAM_H
  13.  
  14. #if !defined( __FSTREAM_H )
  15. #include <fstream.h>
  16. #endif  // __FSTREAM_H
  17.  
  18. #if !defined( __CTYPE_H )
  19. #include <ctype.h>
  20. #endif  // __CTYPE_H
  21.  
  22. #if !defined( __TODOLIST_H )
  23. #include "TodoList.h"
  24. #endif  // __TODOLIST_H
  25.  
  26. #if !defined( __TODODEFS_H )
  27. #include "TodoDefs.h"
  28. #endif  // __TODODEFS_H
  29.  
  30. #if !defined( __TODODLGS_H )
  31. #include "TodoDlgs.h"
  32. #endif  // __TODODLGS_H
  33.  
  34. #include <string.h>
  35. //---------------------------------------------------------------------
  36. //
  37. //  member functions and static data for class TdDate
  38. //
  39. //---------------------------------------------------------------------
  40.  
  41. static char *MonthNames[] =
  42.     {
  43.     "January",
  44.     "February",
  45.     "March",
  46.     "April",
  47.     "May",
  48.     "June",
  49.     "July",
  50.     "August",
  51.     "September",
  52.     "October",
  53.     "November",
  54.     "December"
  55.     };
  56.  
  57. //---------------------------------------------------------------------
  58. //
  59. //  TdDate::TdDate( const char *str );
  60. //
  61. //  constructor that takes a text string.  It's not very bright.
  62. //
  63. //  Format:
  64. //
  65. //      mmm[m*] d[d], yyyy
  66. //
  67. //      mmm must match the first three characters of a valid month
  68. //          name.  Any contiguous characters after these are ignored.
  69. //      dd  must be in the range 1..31.
  70. //      yyyy isn't checked.
  71. //
  72. //  If an invalid date is entered, TdDate will get the current system
  73. //  date.
  74. //
  75. //---------------------------------------------------------------------
  76.  
  77. TdDate::TdDate( const char *str ) : Date()
  78. {
  79.     unsigned M = 0;
  80.     while( M < 12 && strnicmp( str, MonthNames[M], 3 ) != 0 )
  81.         M++;
  82.     if( M >= 12 )
  83.         return;
  84.  
  85.     while( !isspace( *str ) )   // skip month name
  86.         str++;
  87.     while( isspace( *str ) )    // skip trailing whitespace
  88.         str++;
  89.  
  90.     unsigned D, Y;
  91.     istrstream is( (char *)str );
  92.     is >> D;
  93.     if( D < 1 || D > 31 )
  94.         return;
  95.  
  96.     is.get();                   // skip the comma
  97.  
  98.     is >> Y;
  99.     SetMonth( M + 1 );  // 1-based months!
  100.     SetDay( D );
  101.     SetYear( Y );
  102. }
  103.  
  104. //---------------------------------------------------------------------
  105. //
  106. //  member functions for class TodoEntry
  107. //
  108. //---------------------------------------------------------------------
  109.  
  110. int TodoEntry::isEqual( const Object& o ) const
  111. {
  112.     return dateDue == ((const TodoEntry&)o).dateDue;
  113. }
  114.  
  115. int TodoEntry::isLessThan( const Object& o ) const
  116. {
  117.     return dateDue < ((const TodoEntry&)o).dateDue;
  118. }
  119.  
  120. classType TodoEntry::isA() const
  121. {
  122.     return TodoEntryClass;
  123. }
  124.  
  125. char *TodoEntry::nameOf() const
  126. {
  127.     return "Todo Entry";
  128. }
  129.  
  130. hashValueType TodoEntry::hashValue() const
  131. {
  132.     return dateDue.hashValue();
  133. }
  134.  
  135. //---------------------------------------------------------------------
  136. //
  137. //  void TodoEntry::printOn( ostream& os ) const;
  138. //
  139. //  puts a TodoEntry onto an ostream in text form.
  140. //
  141. //---------------------------------------------------------------------
  142.  
  143. void TodoEntry::printOn( ostream& os ) const
  144. {
  145.     char temp[ 256 ];
  146.     ostrstream tstr( temp, sizeof temp );
  147.     tstr << priority
  148.          << '\t'
  149.          << dateCreated
  150.          << '\t'
  151.          << dateDue
  152.          << '\t'
  153.          << ( (text == 0) ? "" : text )
  154.          << ends;
  155.     os << temp;
  156. }
  157.  
  158. //---------------------------------------------------------------------
  159. //
  160. //  istream& operator >> ( istream& is, TodoEntry& td );
  161. //  ostream& operator << ( ostream& os, TodoEntry& td );
  162. //
  163. //  inserter and extractor for TodoEntry.  These work together to
  164. //  write entries out to a stream and read them back in.
  165. //
  166. //---------------------------------------------------------------------
  167.  
  168. istream& operator >> ( istream& is, TodoEntry& td )
  169. {
  170.     is >> td.priority;
  171.     int m, d, y;
  172.     if( is >> m >> d >> y )
  173.         td.dateDue = Date( m+1, d, y );
  174.     if( is >> m >> d >> y )
  175.         td.dateCreated = Date( m+1, d, y );
  176.     char text[ 128 ];
  177.     if( is.getline( text, sizeof text ) )
  178.         td.text = strdup( text );
  179.     td.dirty = FALSE;
  180.     return is;
  181. }
  182.  
  183. ostream& operator << ( ostream& os, TodoEntry& td )
  184. {
  185.     os << td.priority << " "
  186.        << td.dateDue.Month() << " " << td.dateDue.Day() << " "
  187.        << td.dateDue.Year() << " "
  188.        << td.dateCreated.Month() << " " << td.dateCreated.Day() << " "
  189.        << td.dateCreated.Year() << " " << td.text << endl;
  190.     if( os )
  191.         td.dirty = FALSE;
  192.     return os;
  193. }
  194.  
  195. //---------------------------------------------------------------------
  196. //
  197. //  member functions for class TodoList.
  198. //
  199. //---------------------------------------------------------------------
  200.  
  201. void TodoList::add( Object& o )
  202. {
  203.     dirty = TRUE;               // mark that the list has been modified
  204.     SortedArray::add( o );      // add the entry
  205. }
  206.  
  207. void TodoList::detach( Object& o, DeleteType d )
  208. {
  209.     dirty = TRUE;               // mark that the list has been modified
  210.     SortedArray::detach( o, d );// remove the entry
  211. }
  212.  
  213. int TodoList::indexOf( const TodoEntry& tde )
  214. {
  215.     for( int i = 0; i < getItemsInContainer(); i++ )
  216.         if( (*this)[i] == tde )
  217.             return i;
  218.     return -1;
  219. }
  220.  
  221. BOOL TodoList::modified()
  222. {
  223.     if( dirty == TRUE )         // if we've added or deleted entries
  224.         return TRUE;            // we've been modified
  225.                                 // otherwise, if any entry has been
  226.                                 // modified, the list has been modified.
  227.  
  228.     ContainerIterator& ci = initIterator();
  229.     while( ci != 0 )
  230.         {
  231.         TodoEntry& ent = (TodoEntry&)ci++;
  232.         if( ent != NOOBJECT && ent.modified() == TRUE )
  233.             {
  234.             delete &ci;
  235.             return TRUE;
  236.             }
  237.         }
  238.     delete &ci;
  239.     return FALSE;
  240. }
  241.  
  242. void TodoList::clear()
  243. {
  244.     int count = getItemsInContainer();
  245.     for( int i = 0; i < count; i++ )
  246.         if( (*this)[i] != NOOBJECT )
  247.         destroy( i );
  248. }
  249.  
  250. //---------------------------------------------------------------------
  251. //
  252. //  istream& operator >> ( istream& is, TodoList& tl );
  253. //  ostream& operator << ( ostream& os, TodoList& tl );
  254. //
  255. //  inserter and extractor for TodoList.  These work together to
  256. //  write lists out to a stream and read them back in.
  257. //
  258. //---------------------------------------------------------------------
  259.  
  260. istream& operator >> ( istream& is, TodoList& tl )
  261. {
  262.     do  {
  263.         TodoEntry td;
  264.         is >> td;
  265.         if( !is.eof() )
  266.             {
  267.             tl.add( *(new TodoEntry( td )) );
  268.             tl.dirty = FALSE;
  269.             }
  270.         } while( !is.eof() );
  271.     return is;
  272. }
  273.  
  274. ostream& operator << ( ostream& os, TodoList& tl )
  275. {
  276.     ContainerIterator& ci = tl.initIterator();
  277.     while( ci != 0 )
  278.         {
  279.         TodoEntry& ent = (TodoEntry&)(ci++);
  280.         if( ent != NOOBJECT )
  281.             os << ent;
  282.         }
  283.     if( os )
  284.         tl.dirty = FALSE;
  285.     delete &ci;
  286.     return os;
  287. }
  288.  
  289. //---------------------------------------------------------------------
  290. //
  291. //  member functions for class ListBox.
  292. //
  293. //---------------------------------------------------------------------
  294.  
  295. //---------------------------------------------------------------------
  296. //
  297. //  const ListBox& ListBox::operator = ( const TodoList& tdl );
  298. //
  299. //  copies the contents of a TodoList into a ListBox.
  300. //
  301. //---------------------------------------------------------------------
  302.  
  303. const ListBox& ListBox::operator = ( const TodoList& tdl )
  304. {
  305.     assert( hListBox != 0 );
  306.  
  307.     clear();
  308.  
  309.     ContainerIterator& ci = tdl.initIterator();
  310.     while( ci != 0 )
  311.         {
  312.         Object& cur = ci++;
  313.         if( cur != NOOBJECT )
  314.             {
  315.             char buf[100];      // write the entry into a string
  316.                                 // and insert that string into
  317.                                 // the list box
  318.  
  319.             ostrstream( buf, 100 ) << cur << ends;
  320.             SendMessage( hListBox, LB_ADDSTRING, NULL, (LONG)(LPSTR)buf );
  321.             }
  322.         }
  323.     select( 0 );
  324.  
  325.     return *this;
  326. }
  327.  
  328. void ListBox::insert( int i, const TodoEntry& tde )
  329. {
  330.     char temp[100];
  331.     ostrstream( temp, sizeof( temp ) ) << (Object&)tde << ends;
  332.  
  333.     SendMessage( hListBox, LB_INSERTSTRING, i, (LONG)(LPSTR)temp );
  334.     select( i );
  335. }
  336.  
  337. void ListBox::create( HWND owner, HWND hInst, const RECT &wrect )
  338. {
  339.     hListBox = CreateWindow( "ListBox", NULL,
  340.                              LBS_NOTIFY | WS_BORDER | WS_VSCROLL | LBS_USETABSTOPS | WS_CHILD | WS_VISIBLE,
  341.                              wrect.left,
  342.                              wrect.top,
  343.                              wrect.right - wrect.left,
  344.                              wrect.bottom - wrect.top,
  345.                              owner,
  346.                              IDC_LISTBOX,
  347.                              hInst,
  348.                              NULL
  349.                            );
  350.  
  351.     int tabs[] = { 10, 100, 200 };
  352.     SendMessage( hListBox,
  353.                  LB_SETTABSTOPS,
  354.                  sizeof(tabs)/sizeof(*tabs),
  355.                  (LONG)(LPSTR)tabs
  356.                 );
  357.     focus();
  358. }
  359.  
  360. //---------------------------------------------------------------------
  361. //
  362. //  member functions for class TodoWindow.
  363. //
  364. //  these are mostly self-explanatory.
  365. //
  366. //---------------------------------------------------------------------
  367.  
  368. BOOL TodoWindow::registerClass()
  369. {
  370.     WNDCLASS wc;
  371.  
  372.     wc.style = 0;
  373.     wc.lpfnWndProc = &Window::wndProc;
  374.     wc.cbClsExtra = 0;
  375.     wc.cbWndExtra = 0;
  376.     wc.hInstance = hInst;
  377.     wc.hIcon = LoadIcon( NULL, IDI_APPLICATION );
  378.     wc.hCursor = LoadCursor( NULL, IDC_ARROW );
  379.     wc.hbrBackground = GetStockObject( WHITE_BRUSH );
  380.     wc.lpszMenuName = "TodoMenu";
  381.     wc.lpszClassName = "TodoClass";
  382.  
  383.     return RegisterClass( &wc );
  384. }
  385.  
  386. BOOL TodoWindow::createWindow()
  387. {
  388.     hWindow = CreateWindow(
  389.                 "TodoClass",
  390.                 "Todo List",
  391.                 WS_OVERLAPPEDWINDOW,
  392.                 CW_USEDEFAULT,
  393.                 CW_USEDEFAULT,
  394.                 CW_USEDEFAULT,
  395.                 CW_USEDEFAULT,
  396.                 NULL,
  397.                 NULL,
  398.                 hInst,
  399.                 NULL
  400.                 );
  401.     if( hWnd() == 0 )
  402.         return FALSE;
  403.  
  404.     insert();                   // insert this window into the window list
  405.  
  406.     RECT wrect;
  407.     GetClientRect( hWnd(), (LPRECT) &wrect);
  408.     listBox.create( hWnd(), hInst, wrect );
  409.                                 // build a list box in the client rectangle
  410.     listBox = tdl;              // copy the Todo list into the list box
  411.  
  412.     ShowWindow( hWnd(), show );
  413.     UpdateWindow( hWnd() );
  414.     return TRUE;
  415. }
  416.  
  417. void TodoWindow::aboutBox()
  418. {
  419.     AboutBox ab( hWnd() );
  420.     ab.run();
  421. }
  422.  
  423. void TodoWindow::editBox()
  424. {
  425.     int cur = listBox.current();
  426.     if( cur == -1 )
  427.         {
  428.         newEntry();             // if there's nothing in the list,
  429.         return;                 // need to create an entry
  430.         }
  431.  
  432.     EditBox ed( hWnd(), (TodoEntry&)tdl[ cur ] );
  433.     ed.run();
  434.  
  435.     listBox.replace( cur, (TodoEntry&)tdl[ cur ] );
  436. }
  437.  
  438. void TodoWindow::newEntry()
  439. {
  440.     TodoEntry *tde = new TodoEntry();
  441.     EditBox ed( hWnd(), *tde );
  442.  
  443.     if( ed.run() != 0 )         // ed.run() returns 0 if terminated by
  444.         delete tde;             // OK, 1 if terminated by Cancel.
  445.     else
  446.         {
  447.         tdl.add( *tde );
  448.         listBox.insert( tdl.indexOf( *tde ), *tde );
  449.         }
  450. }
  451.  
  452. void TodoWindow::delEntry()
  453. {
  454.     int cur = listBox.current();
  455.     if( cur == -1 )             // if there's nothing in the list, there's
  456.         return;                 // nothing to delete.
  457.     tdl.destroy( cur );
  458.     listBox.remove( cur );
  459.     listBox.select( cur );
  460. }
  461.  
  462. void TodoWindow::moveListBox()
  463. {
  464.     RECT wrect;
  465.     GetClientRect( hWnd(), (LPRECT) &wrect);
  466.  
  467.     listBox.move( wrect );
  468. }
  469.  
  470. //---------------------------------------------------------------------
  471. //
  472. //  void TodoWindow::checkSave();
  473. //
  474. //  checks whether the Todo list has been modified.  If it has, asks
  475. //  the user whether to save the list or not, and if it is to be saved,
  476. //  writes it to a file.
  477. //
  478. //---------------------------------------------------------------------
  479.  
  480. void TodoWindow::checkSave()
  481. {
  482.     if( tdl.modified() == TRUE && saveBox() == TRUE )
  483.         {
  484.         if( fileName == 0 )
  485.             if( getFileName( "Write to:", FALSE ) == FALSE )
  486.                 return;
  487.         writeFile();
  488.         }
  489. }
  490.  
  491. void TodoWindow::newList()
  492. {
  493.     checkSave();                // dump the current list
  494.     tdl.clear();
  495.     listBox.clear();
  496.     delete fileName;
  497.     fileName = 0;               // mark that there's no file
  498. }
  499.  
  500. void TodoWindow::openFile()
  501. {
  502.     checkSave();                // dump the current list
  503.     tdl.clear();
  504.     listBox.clear();
  505.     if( getFileName( "Read from:", TRUE ) == TRUE )
  506.         readFile();             // read new data from the specified file
  507. }
  508.  
  509. void TodoWindow::saveFile()
  510. {
  511.     if( fileName == 0 )
  512.         if( getFileName( "Write to:", FALSE ) == FALSE )
  513.             return;
  514.     writeFile();
  515. }
  516.  
  517. void TodoWindow::saveFileAs()
  518. {
  519.     if( getFileName( "Write to:", FALSE ) == TRUE )
  520.         writeFile();
  521. }
  522.  
  523. BOOL TodoWindow::getFileName( const char *caption, BOOL me )
  524. {
  525.     char curdir[ MAXDIR ];
  526.     getcwd( curdir, sizeof curdir );
  527.     FileBox fb( hWnd(), caption, curdir, "*.tdo", me );
  528.  
  529.     if( fb.run() != 0 )
  530.         return FALSE;
  531.  
  532.     delete fileName;
  533.     fileName = strdup( fb.getPath() );
  534.     return TRUE;
  535. }
  536.  
  537. void TodoWindow::readFile()
  538. {
  539.     ifstream in( fileName );    // open the input file
  540.     assert( in );
  541.     in >> tdl;                  // read the Todo list
  542.     listBox = tdl;              // build the list box
  543. }
  544.  
  545. void TodoWindow::writeFile()
  546. {
  547.     ofstream out( fileName );
  548.     assert( out );
  549.     out << tdl;
  550. }
  551.  
  552. BOOL TodoWindow::saveBox()
  553. {
  554.     if( MessageBox( hWnd(),
  555.                     "Save Changes",
  556.                     "Current List Modified",
  557.                     MB_YESNO | MB_ICONQUESTION
  558.                 ) == IDYES )
  559.         return TRUE;
  560.     else
  561.         return FALSE;
  562. }
  563.  
  564. //---------------------------------------------------------------------
  565. //
  566. //  BOOL TodoWindow::processCommand( WORD wParam, long lParam );
  567. //
  568. //  dispatches commands to the appropriate member functions.
  569. //
  570. //---------------------------------------------------------------------
  571.  
  572. BOOL TodoWindow::processCommand( WORD wParam, long lParam )
  573. {
  574.     switch( wParam )
  575.         {
  576.  
  577.         case IDM_QUIT:
  578.             SendMessage(hWnd(), WM_CLOSE, 0, 0L);
  579.             return TRUE;
  580.  
  581.         case IDM_NEW_LIST:
  582.             newList();
  583.             return TRUE;
  584.  
  585.         case IDM_OPEN:
  586.             openFile();
  587.             return TRUE;
  588.  
  589.         case IDM_SAVE:
  590.             saveFile();
  591.             return TRUE;
  592.  
  593.         case IDM_SAVEAS:
  594.             saveFileAs();
  595.             return TRUE;
  596.  
  597.         case IDM_EDIT:
  598.             editBox();
  599.             return TRUE;
  600.  
  601.         case IDM_NEW_ENTRY:
  602.             newEntry();
  603.             return TRUE;
  604.  
  605.         case IDM_DEL_ENTRY:
  606.             delEntry();
  607.             return TRUE;
  608.  
  609.         case IDM_ABOUT:
  610.             aboutBox();
  611.             return TRUE;
  612.  
  613.         case IDC_LISTBOX:
  614.             if( HIWORD( lParam ) == LBN_DBLCLK )
  615.                 {
  616.                 editBox();
  617.                 return TRUE;
  618.                 }
  619.             else
  620.                 return FALSE;
  621.         default:
  622.             return FALSE;
  623.         }
  624. }
  625.  
  626. //---------------------------------------------------------------------
  627. //
  628. //  LONG TodoWindow::dispatch( WORD msg, WORD wParam, long lParam );
  629. //
  630. //  dispatches messages to the appropriate member functions.
  631. //
  632. //---------------------------------------------------------------------
  633.  
  634. LONG TodoWindow::dispatch( WORD msg, WORD wParam, long lParam )
  635. {
  636.     switch( msg )
  637.         {
  638.         case WM_COMMAND:
  639.  
  640.             if( processCommand( wParam, lParam ) == TRUE )
  641.                 {
  642.                 listBox.focus();
  643.                 return 0;
  644.                 }
  645.             break;
  646.  
  647.         case WM_MOVE:
  648.         case WM_SIZE:
  649.  
  650.             moveListBox();
  651.             return 0;
  652.  
  653.         case WM_QUERYENDSESSION:
  654.             return TRUE;
  655.  
  656.         case WM_CLOSE:
  657.  
  658.             checkSave();
  659.             DestroyWindow( hWnd() );
  660.             return 0;
  661.  
  662.         case WM_DESTROY:
  663.         case WM_QUIT:
  664.  
  665.             PostQuitMessage( 0 );
  666.             break;
  667.         }
  668.         return Window::dispatch( msg, wParam, lParam );
  669. }
  670.  
  671. //---------------------------------------------------------------------
  672. //
  673. //  int PASCAL WinMain( HANDLE, HANDLE, LPSTR, int );
  674. //
  675. //  the main entry point for the program.
  676. //
  677. //---------------------------------------------------------------------
  678.  
  679. extern "C" {
  680. int PASCAL WinMain( HANDLE h, HANDLE hPrev, LPSTR s, int n)
  681. {
  682.     TodoWindow td;
  683.     td.create();
  684.     return td.run();
  685. }
  686. }
  687.  
  688.